﻿2026-08-08T22:31:59.8293143Z ##[group]Run set -euo pipefail
2026-08-08T22:31:59.8293512Z [36;1mset -euo pipefail[0m
2026-08-08T22:31:59.8293852Z [36;1mmkdir -p /tmp/financemanager-phase3-backend/runtime[0m
2026-08-08T22:31:59.8294353Z [36;1mpython -m pytest tests -q | tee /tmp/financemanager-phase3-backend/pytest.log[0m
2026-08-08T22:31:59.8295421Z [36;1mpassed_count=$(sed -nE 's/.*(^|[^0-9])([0-9]+) passed.*/\2/p' /tmp/financemanager-phase3-backend/pytest.log | tail -n 1)[0m
2026-08-08T22:31:59.8295969Z [36;1mtest -n "${passed_count}"[0m
2026-08-08T22:31:59.8296463Z [36;1mtest "${passed_count}" -ge 667[0m
2026-08-08T22:31:59.8347228Z shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
2026-08-08T22:31:59.8347596Z env:
2026-08-08T22:31:59.8347801Z   PYTHONPATH: src
2026-08-08T22:31:59.8348025Z   JARVIS_FINANCE_ENV: test
2026-08-08T22:31:59.8348390Z   JARVIS_FINANCE_DB_PATH: /tmp/financemanager-phase3-backend/finance.sqlite3
2026-08-08T22:31:59.8348891Z   JARVIS_FINANCE_RUNTIME_DIR: /tmp/financemanager-phase3-backend/runtime
2026-08-08T22:31:59.8349328Z   JARVIS_FINANCE_WRITE_MODE: disabled
2026-08-08T22:31:59.8349661Z   pythonLocation: /opt/hostedtoolcache/Python/3.11.15/x64
2026-08-08T22:31:59.8350110Z   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib/pkgconfig
2026-08-08T22:31:59.8350562Z   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
2026-08-08T22:31:59.8350947Z   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
2026-08-08T22:31:59.8351332Z   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.11.15/x64
2026-08-08T22:31:59.8351732Z   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.15/x64/lib
2026-08-08T22:31:59.8352061Z ##[endgroup]
2026-08-08T22:32:17.3513466Z ........................................................................ [  7%]
2026-08-08T22:32:30.3051996Z ........................................................................ [ 14%]
2026-08-08T22:32:42.9394565Z ........................................................................ [ 21%]
2026-08-08T22:32:57.6717788Z ........................................................................ [ 28%]
2026-08-08T22:33:09.8802724Z ........................................................................ [ 35%]
2026-08-08T22:33:20.9125518Z ........................................................................ [ 42%]
2026-08-08T22:33:31.8822439Z ........................................................................ [ 50%]
2026-08-08T22:33:51.4510375Z ........................................................................ [ 57%]
2026-08-08T22:34:05.2797813Z ........................................................................ [ 64%]
2026-08-08T22:34:29.7416163Z ........................................................................ [ 71%]
2026-08-08T22:34:47.1982378Z ........................................................................ [ 78%]
2026-08-08T22:34:58.9480982Z ........................................................................ [ 85%]
2026-08-08T22:35:10.7754407Z ........F............................................................... [ 93%]
2026-08-08T22:35:26.1567138Z .....................................................................    [100%]
2026-08-08T22:35:26.1568082Z =================================== FAILURES ===================================
2026-08-08T22:35:26.1569123Z ____ test_read_only_api_allows_preview_but_blocks_confirm_without_mutation _____
2026-08-08T22:35:26.1569788Z 
2026-08-08T22:35:26.1570280Z     def test_read_only_api_allows_preview_but_blocks_confirm_without_mutation():
2026-08-08T22:35:26.1571109Z         conn = database()
2026-08-08T22:35:26.1571694Z         add_bank_row(conn, "bank-1", "2026-01-30", "600")
2026-08-08T22:35:26.1572368Z         app = create_app(write_mode="disabled")
2026-08-08T22:35:26.1573027Z         app.dependency_overrides[get_db] = lambda: conn
2026-08-08T22:35:26.1573659Z         client = TestClient(app)
2026-08-08T22:35:26.1574178Z         body = {
2026-08-08T22:35:26.1574627Z             "period_from": "2026-01-01",
2026-08-08T22:35:26.1575411Z             "period_to": "2026-07-31",
2026-08-08T22:35:26.1576855Z             "recipient_name": "Example Recipient",
2026-08-08T22:35:26.1577449Z             "recipient_account_identity": None,
2026-08-08T22:35:26.1578019Z             "counterparty_hashes": ["a" * 64],
2026-08-08T22:35:26.1578574Z             "reference_tokens": [],
2026-08-08T22:35:26.1579266Z             "attestation": "Preview only; no recipient rule or cashflow is activated.",
2026-08-08T22:35:26.1579980Z         }
2026-08-08T22:35:26.1580627Z         before = conn.total_changes
2026-08-08T22:35:26.1581142Z         response = client.post(
2026-08-08T22:35:26.1581798Z             "/api/portfolio/performance/truewealth-bank-payments/preview",
2026-08-08T22:35:26.1582472Z             json=body,
2026-08-08T22:35:26.1582898Z         )
2026-08-08T22:35:26.1583326Z         assert response.status_code == 200
2026-08-08T22:35:26.1583919Z         assert response.json()["counts"]["secure"] == 1
2026-08-08T22:35:26.1584512Z         assert conn.total_changes == before
2026-08-08T22:35:26.1585327Z         for path in (
2026-08-08T22:35:26.1586110Z             "/api/portfolio/performance/truewealth/view?requested_from=2026-01-01&requested_to=2026-07-31",
2026-08-08T22:35:26.1587119Z             "/api/portfolio/performance/truewealth/model-preview?as_of=2026-07-31",
2026-08-08T22:35:26.1587816Z         ):
2026-08-08T22:35:26.1588241Z             readonly = client.get(path)
2026-08-08T22:35:26.1588831Z             assert readonly.status_code == 200, readonly.text
2026-08-08T22:35:26.1589451Z             assert conn.total_changes == before
2026-08-08T22:35:26.1590006Z         package = client.post(
2026-08-08T22:35:26.1590649Z             "/api/portfolio/performance/truewealth/activation-package-preview",
2026-08-08T22:35:26.1591334Z             json={
2026-08-08T22:35:26.1591750Z                 **body,
2026-08-08T22:35:26.1592225Z                 "performance_from": "2026-01-01",
2026-08-08T22:35:26.1592784Z                 "performance_to": "2026-07-31",
2026-08-08T22:35:26.1593333Z                 "model_as_of": "2026-07-31",
2026-08-08T22:35:26.1593843Z             },
2026-08-08T22:35:26.1594242Z         )
2026-08-08T22:35:26.1594842Z         assert package.status_code == 200, package.text
2026-08-08T22:35:26.1595592Z         assert package.json()["activation_package"]["production_writes"] == 0
2026-08-08T22:35:26.1596305Z         model_payload = client.get(
2026-08-08T22:35:26.1596979Z             "/api/portfolio/performance/truewealth/model-preview?as_of=2026-07-31"
2026-08-08T22:35:26.1597661Z         ).json()
2026-08-08T22:35:26.1598103Z >       assert set(model_payload) == {
2026-08-08T22:35:26.1598766Z             "as_of", "account_id", "status", "quality_status", "reason_codes",
2026-08-08T22:35:26.1599567Z             "modelled_value_chf", "latest_price_fx_date", "latest_modelled_value",
2026-08-08T22:35:26.1600256Z             "input_fingerprint",
2026-08-08T22:35:26.1600732Z         }
2026-08-08T22:35:26.1601361Z E       AssertionError: assert {'account_id'...fx_date', ...} == {'account_id'...lue_chf', ...}
2026-08-08T22:35:26.1602122Z E         
2026-08-08T22:35:26.1602545Z E         Extra items in the left set:
2026-08-08T22:35:26.1603048Z E         'anchor_date'
2026-08-08T22:35:26.1603498Z E         'net_external_cashflows_chf'
2026-08-08T22:35:26.1603988Z E         
2026-08-08T22:35:26.1604371Z E         Full diff:
2026-08-08T22:35:26.1605026Z E           {
2026-08-08T22:35:26.1605458Z E               'account_id',
2026-08-08T22:35:26.1605962Z E         +     'anchor_date',
2026-08-08T22:35:26.1606434Z E               'as_of',
2026-08-08T22:35:26.1606902Z E               'input_fingerprint',
2026-08-08T22:35:26.1607419Z E               'latest_modelled_value',
2026-08-08T22:35:26.1607946Z E               'latest_price_fx_date',
2026-08-08T22:35:26.1608470Z E               'modelled_value_chf',
2026-08-08T22:35:26.1609067Z E         +     'net_external_cashflows_chf',
2026-08-08T22:35:26.1609607Z E               'quality_status',
2026-08-08T22:35:26.1610110Z E               'reason_codes',
2026-08-08T22:35:26.1610820Z E               'status',
2026-08-08T22:35:26.1611276Z E           }
2026-08-08T22:35:26.1611562Z 
2026-08-08T22:35:26.1612026Z tests/unit/test_sprint20d_truewealth_productization.py:680: AssertionError
2026-08-08T22:35:26.1612867Z =============================== warnings summary ===============================
2026-08-08T22:35:26.1613794Z ../../../../../opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/fastapi/testclient.py:1
2026-08-08T22:35:26.1615814Z   /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
2026-08-08T22:35:26.1617383Z     from starlette.testclient import TestClient as TestClient  # noqa
2026-08-08T22:35:26.1617941Z 
2026-08-08T22:35:26.1618409Z -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
2026-08-08T22:35:26.1619281Z =========================== short test summary info ============================
2026-08-08T22:35:26.1621025Z FAILED tests/unit/test_sprint20d_truewealth_productization.py::test_read_only_api_allows_preview_but_blocks_confirm_without_mutation - AssertionError: assert {'account_id'...fx_date', ...} == {'account_id'...lue_chf', ...}
2026-08-08T22:35:26.1622506Z   
2026-08-08T22:35:26.1622921Z   Extra items in the left set:
2026-08-08T22:35:26.1623402Z   'anchor_date'
2026-08-08T22:35:26.1623848Z   'net_external_cashflows_chf'
2026-08-08T22:35:26.1624317Z   
2026-08-08T22:35:26.1624842Z   Full diff:
2026-08-08T22:35:26.1625244Z     {
2026-08-08T22:35:26.1625634Z         'account_id',
2026-08-08T22:35:26.1626067Z   +     'anchor_date',
2026-08-08T22:35:26.1626575Z         'as_of',
2026-08-08T22:35:26.1627004Z         'input_fingerprint',
2026-08-08T22:35:26.1627487Z         'latest_modelled_value',
2026-08-08T22:35:26.1627978Z         'latest_price_fx_date',
2026-08-08T22:35:26.1628468Z         'modelled_value_chf',
2026-08-08T22:35:26.1628953Z   +     'net_external_cashflows_chf',
2026-08-08T22:35:26.1629459Z         'quality_status',
2026-08-08T22:35:26.1629916Z         'reason_codes',
2026-08-08T22:35:26.1630349Z         'status',
2026-08-08T22:35:26.1630750Z     }
2026-08-08T22:35:26.1631213Z 1 failed, 1004 passed, 1 warning in 205.31s (0:03:25)
2026-08-08T22:35:26.5367689Z ##[error]Process completed with exit code 1.
